﻿using System;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Windows.Input;
using Microsoft.Popfly.GameCreator.GameEngine.Events;
using System.Windows;
#if !PHONE
using Microsoft.Popfly.GameCreator.GameEngine.Behaviors.JSRuntime;
#endif
using System.Runtime.CompilerServices;
using System.Linq;
using Microsoft.Popfly.GameCreator.GameEngine.Behaviors;
#if !PHONE
using Microsoft.Scripting.Runtime;
#endif

namespace Microsoft.Popfly.GameCreator.GameEngine
{
    public abstract class BehaviorOwner : PropertyHolder
    {
        public string Name { get; protected set; }

        public abstract double X { get; set; }
        public abstract double Y { get; set; }
        public double XVelocity { get; set; }
        public double YVelocity { get; set; }
        public double XAcceleration { get; set; }
        public double YAcceleration { get; set; }
        private double m_xDrag, m_yDrag;
        public double XDrag
        {
            get
            {
                return m_xDrag;
            }
            set
            {
                if (value > 1.0)
                {
                    m_xDrag = 1.0;
                    Console.ReportError("Error: Cannot set XDrag on '" + Name + "' to '" + value +
                        "'.  Drag properties must be between 0 and 1.0.  Setting drag to 1.0.  ");

                }
                else if (value < 0.0)
                {
                    m_xDrag = 0.0;
                    Console.ReportError("Error: Cannot set XDrag on '" + Name + "' to '" + value +
                        "'.  Drag properties must be between 0 and 1.0.  Setting drag to 0.0.  ");
                }
                else
                {
                    m_xDrag = value;
                }
            }
        }
        public double YDrag
        {
            get
            {
                return m_yDrag;
            }
            set
            {
                if (value > 1.0)
                {
                    m_yDrag = 1.0;
                    Console.ReportError("Error: Cannot set YDrag on '" + Name + "' to '" + value +
                        "'.  Drag properties must be between 0 and 1.0.  Setting drag to 1.0.  ");

                }
                else if (value < 0.0)
                {
                    m_yDrag = 0.0;
                    Console.ReportError("Error: Cannot set yDrag on '" + Name + "' to '" + value +
                        "'.  Drag properties must be between 0 and 1.0.  Setting drag to 0.0.  ");
                }
                else
                {
                    m_yDrag = value;
                }
            }
        }

        public abstract double Width { get; set; }
        public abstract double Height { get; set; }

        public bool IsActor { get; protected set; }

        internal bool FinishedFirstUpdate { get; private set; }

        private List<StandardListener> m_standardEventListeners = new List<StandardListener>();
        private List<StandardListener> m_propertyChangeEventListeners = new List<StandardListener>();
        private List<CollisionListener> m_collisionEventListeners = new List<CollisionListener>();
        protected List<DisappearListener> m_disappearEventListeners = new List<DisappearListener>();
        protected bool m_queueDisappearRemoves = false;
        internal Game m_game;
        private Scene m_scene;
        internal Scene Scene { get { return m_scene; } }

        // Removes must be queued during the behaviors update so the enumeration will still work 
        private bool m_queueRemoves;
        private List<EventListener> m_eventsToRemove = new List<EventListener>();


        public IEnumerable<EventListener> Listeners
        {
            get
            {
                return
                    (from listener in m_collisionEventListeners select ((EventListener)listener)).Union
                    (from listener in m_standardEventListeners select ((EventListener)listener)).Union
                    (from listener in m_disappearEventListeners select ((EventListener)listener)).Union
                    (from listener in m_propertyChangeEventListeners select ((EventListener)listener));
            }
        }
        public IEnumerable<IBehavior> Behaviors
        {
            get
            {
                return from listener in Listeners select listener.Behavior;
            }
        }

        public void BehaviorsUpdate(double elapsedTimeInSeconds)
        {
            System.Diagnostics.Debug.Assert(m_behaviorsInited);
            m_queueRemoves = true;
            int count = m_standardEventListeners.Count;
            for (int i = 0; i < count; i++)
            {
                m_standardEventListeners[i].Update(elapsedTimeInSeconds);
            }
            m_queueRemoves = false;

            foreach (EventListener eventToRemove in m_eventsToRemove)
            {
                RemoveBehavior(eventToRemove);
            }
            m_eventsToRemove.Clear();

            FinishedFirstUpdate = true;
        }
        public void PropertyChangeEventBehaviorsUpdate(double elapsedTimeInSeconds)
        {
            System.Diagnostics.Debug.Assert(m_behaviorsInited);
            m_queueRemoves = true;
            int count = m_propertyChangeEventListeners.Count;
            for (int i = 0; i < count; i++)
            {
                m_propertyChangeEventListeners[i].Update(elapsedTimeInSeconds);
            }
            m_queueRemoves = false;

            foreach (EventListener eventToRemove in m_eventsToRemove)
            {
                RemoveBehavior(eventToRemove);
            }
            m_eventsToRemove.Clear();
        }

        public BehaviorOwner(Game game, String name)
        {
            m_game = game;
            m_queueRemoves = false;
            Name = name;
            FinishedFirstUpdate = false;
        }
        private bool m_behaviorsInited = false;
        protected void InitBehaviors(Scene scene, Collections.OrderedDictionary<String, Data.BehaviorInfo> behaviors)
        {
            m_behaviorsInited = true;

            m_scene = scene;

            if (behaviors != null)
            {
                for (int i = 0; i < behaviors.Count; i++)
                {
                    Data.BehaviorInfo behaviorInfo = behaviors.getIndexedValue(i);
                    AddBehavior(behaviorInfo);
                }
            }
        }

        internal void CheckForChangedProperties()
        {
            m_queueRemoves = true;
            foreach (StandardListener listener in m_propertyChangeEventListeners)
            {
                ((IPropertyEventChecker)listener.EventChecker).CheckForChange();
            }
            m_queueRemoves = false;

            foreach (EventListener eventToRemove in m_eventsToRemove)
            {
                RemoveBehavior(eventToRemove);
            }
            m_eventsToRemove.Clear();
        }

        internal void InitPropertyChangePreviousValues()
        {
            foreach (StandardListener listener in m_propertyChangeEventListeners)
            {
                ((IPropertyEventChecker)listener.EventChecker).InitPreviousValue();
            }
        }

        private void AddCollisionBehavior(CollisionListener collisionListener)
        {
            m_scene.AddCollisionListener(collisionListener);
            m_collisionEventListeners.Add(collisionListener);
        }



        internal List<CollisionListener> OrderCollisionBehaviors(List<CollisionListener> unorderedList)
        {
            List<CollisionListener> orderedListeners = new List<CollisionListener>();

            foreach (CollisionListener inOrderListener in m_collisionEventListeners)
            {
                if (unorderedList.Contains(inOrderListener))
                {
                    orderedListeners.Add(inOrderListener);
                }
            }

#if DEBUG
            // Do more checking to make sure every element in unorderedList is in this actor
            foreach (CollisionListener listener in unorderedList)
            {
                if (m_collisionEventListeners.Contains(listener) == false)
                {
                    throw new ArgumentException(
                        Utils.ErrorMessagePrefix +
                        "Error: Collision Listener '" + listener.BehaviorName +
                        "' wasn't found on BehaviorOwner '" + this.Name + "'."
                        );
                }
            }
#endif
            return orderedListeners;
        }

        /// <summary>
        /// Adds the behavior described by behaviorInfo.  
        /// </summary>
        /// <param name="behaviorInfo">A description of the behavior to be added</param>
        /// <returns>If the behavior is created successfully, returns the EventListener class for the behavior.  Otherwise returns null.</returns>
        public EventListener AddBehavior(Data.BehaviorInfo behaviorInfo)
        {
            // only add a behavior if its filter contains the current scene or isn't set
            if (behaviorInfo.Event.Filter == null ||
                behaviorInfo.Event.Filter.SceneReferences == null ||
                (behaviorInfo.Event.Filter.SceneReferences.ContainsKey(Scene.Name))
                )
            {
                Game.EventListenerCount++;
                try
                {
                    if (behaviorInfo.Event.Type == "Disappear")
                    {
                        DisappearListener disappearListener = new DisappearListener(m_game, this, behaviorInfo);
                        m_disappearEventListeners.Add(disappearListener);
                    }
                    else if (behaviorInfo.Event.Type == "collision")
                    {
                        Data.CollisionEventInfo collisionEvent = (Data.CollisionEventInfo)behaviorInfo.Event;
                        if (collisionEvent.CollisionType == "Collision" ||
                            collisionEvent.CollisionType == "CollisionStart")
                        {
                            CollisionListener collisionListener = new CollisionListener(m_game, this, behaviorInfo);
                            AddCollisionBehavior(collisionListener);
                            return collisionListener;
                        }
                        else if (collisionEvent.CollisionType == "CollisionEnd")
                        {
                            StandardListener eventListener = null;
                            eventListener = new StandardListener(m_game, this, behaviorInfo);

                            m_standardEventListeners.Add(eventListener);
                            System.Diagnostics.Debug.Assert(eventListener.EventChecker.GetType().Equals(typeof(CollisionEndChecker)));
                            m_scene.AddCollisionEndListener((CollisionEndChecker)eventListener.EventChecker);
                        }
                        else
                        {
                            throw new System.NotImplementedException(
                                Utils.ErrorMessagePrefix +
                                "Add Behavior doesn't know how to handle collision events with a collision type of '" +
                                collisionEvent.CollisionType +
                                "'."
                                );
                        }
                    }
                    else if (behaviorInfo.Event.Type == "PropertyChange")
                    {
                        StandardListener eventListener = new StandardListener(m_game, this, behaviorInfo);
                        m_propertyChangeEventListeners.Add(eventListener);
                        return eventListener;
                    }
                    else
                    {
                        StandardListener eventListener = null;
                        eventListener = new StandardListener(m_game, this, behaviorInfo);

                        m_standardEventListeners.Add(eventListener);
                        return eventListener;
                    }
                }
                catch (Exception exception)
                {
                    Console.ReportError("Error adding behavior '" + behaviorInfo.Name + "' on object '" + Name + "'.\n" +
                        "Message: '" + exception.Message + "'\n" +
                        "Exception: \n" + exception.ToString());
                }
            }
            return null;
        }

        /// <summary>
        /// Adds the behavior described by behaviorInfo.  
        /// </summary>
        /// <param name="behaviorInfo">A description of the behavior to be added</param>
        /// <returns>If the behavior is created successfully, returns the EventListener class for the behavior.  Otherwise returns null.</returns>
        public EventListener AddBehavior(EventListener eventListener)
        {
            // Only add the behavior if it doesn't filter out the current scene.
            if (eventListener.Filter == null ||
                eventListener.Filter.Scenes == null ||
                (eventListener.Filter.Scenes.ContainsKey(Scene.Name) && eventListener.Filter.Scenes[Scene.Name])
                )
            {
                Game.EventListenerCount++;

                if (eventListener.GetType() == typeof(CollisionListener))
                {
                    AddCollisionBehavior((CollisionListener)eventListener);
                }
                else if (eventListener.GetType() == typeof(StandardListener))
                {
                    StandardListener standardListener = (StandardListener)eventListener;
                    Type eventType = standardListener.EventChecker.GetType();
                    if (standardListener.EventChecker is IPropertyEventChecker)
                    {
                        m_propertyChangeEventListeners.Add(standardListener);
                    }
                    else if (eventType == typeof(CollisionEndChecker))
                    {
                        m_standardEventListeners.Add(standardListener);
                        m_scene.AddCollisionEndListener((CollisionEndChecker)standardListener.EventChecker);
                    }
                    else
                    {
                        m_standardEventListeners.Add(standardListener);
                    }
                }
                else if (eventListener.GetType() == typeof(DisappearListener))
                {
                    m_disappearEventListeners.Add((DisappearListener)eventListener);
                }
                else
                {
                    throw new NotImplementedException(
                        Utils.ErrorMessagePrefix +
                        "Add behavior doesn't understand how to add event listeners of type '" +
                        eventListener.GetType().ToString() +
                        "' yet."
                        );
                }

                return eventListener;
            }

            return null;
        }

        /// <summary>
        /// Searches current behaviors for a behavior whose name matches behaviorName.  Removes the first 
        /// behavior of that name found.
        /// </summary>
        /// <param name="behaviorName">The name of the behavior you would like to remove</param>
        /// <returns>true if an behavior of that name is found and removed, false otherwise.
        /// In the event that the BehaviorOwner is currently executing its behaviors, 
        /// the event will be queued for later removal and the function will immediately return true.</returns>
        public bool RemoveBehavior(string behaviorName)
        {
            // try to find it in standard listeners
            foreach (StandardListener listener in m_standardEventListeners)
            {
                if (listener.BehaviorName == behaviorName)
                {
                    return RemoveBehavior(listener);
                }
            }
            // try to find it in collision listeners
            foreach (CollisionListener listener in m_collisionEventListeners)
            {
                if (listener.BehaviorName == behaviorName)
                {
                    return RemoveBehavior(listener);
                }
            }
            // try to find it in disappear listeners
            foreach (DisappearListener listener in m_disappearEventListeners)
            {
                if (listener.BehaviorName == behaviorName)
                {
                    return RemoveBehavior(listener);
                }
            }
            // try to find it in property change listeners
            foreach (StandardListener listener in m_propertyChangeEventListeners)
            {
                if (listener.BehaviorName == behaviorName)
                {
                    return RemoveBehavior(listener);
                }
            }
            return false;
        }

#if !PHONE
        /// <summary>
        /// Searches current behaviors for an InvokeFunction behavior whose javascript function matches invokeFunction.  Removes the first 
        /// behavior  found.
        /// </summary>
        /// <param name="behaviorName">The FunctionObject whose behavior you would like to remove</param>
        /// <returns>true if an behavior of that name is found and removed, false otherwise.
        /// In the event that the BehaviorOwner is currently executing its behaviors, 
        /// the event will be queued for later removal and the function will immediately return true.</returns>
        public bool RemoveBehavior(string eventName, Microsoft.JScript.Runtime.Types.FunctionObject function)
        {
            // try to find it in standard listeners
            foreach (StandardListener listener in m_standardEventListeners)
            {
                if (listener.EventChecker.IsOfEventType(eventName) &&
                    listener.Behavior is JSRuntimeExtensions.InvokedFunction &&
                    ((JSRuntimeExtensions.InvokedFunction)listener.Behavior).Function == function)
                {
                    return RemoveBehavior(listener);
                }
            }
            if (eventName == "collision")
            {
                // try to find it in collision listeners
                foreach (CollisionListener listener in m_collisionEventListeners)
                {
                    if (listener.Behavior is JSRuntimeExtensions.InvokedFunction &&
                        ((JSRuntimeExtensions.InvokedFunction)listener.Behavior).Function == function)
                    {
                        return RemoveBehavior(listener);
                    }
                }
            }
            if (eventName == "disappear")
            {
                // try to find it in disappear listeners
                foreach (DisappearListener listener in m_disappearEventListeners)
                {
                    if (listener.Behavior is JSRuntimeExtensions.InvokedFunction &&
                        ((JSRuntimeExtensions.InvokedFunction)listener.Behavior).Function == function)
                    {
                        return RemoveBehavior(listener);
                    }
                }
            }

            if (eventName == "PropertyChange")
            {
                // try to find it in property change listeners
                foreach (StandardListener listener in m_propertyChangeEventListeners)
                {
                    if (listener.Behavior is JSRuntimeExtensions.InvokedFunction &&
                        ((JSRuntimeExtensions.InvokedFunction)listener.Behavior).Function == function)
                    {
                        return RemoveBehavior(listener);
                    }
                }
            }

            return false;
        }
#endif

        /// <summary>
        /// Searches current behaviors for the instance of behavior passed in.  Removes the first 
        /// instance found so it will no longer be executed when its event occurs.
        /// </summary>
        /// <param name="behavior">The behavior parameter returned as part of an EventListener from AddBehavior</param>
        /// <returns>true if the behavior is successfully removed; otherwise, false.  
        /// This method also returns false if the behavior was not found.
        /// In the event that the BehaviorOwner is currently executing its behaviors, 
        /// the event will be queued for later removal and the function will immediately return true.</returns>
        public bool RemoveBehavior(Behaviors.IBehavior behavior)
        {
            // try to find it in standard listeners
            foreach (StandardListener listener in m_standardEventListeners)
            {
                if (listener.Behavior == behavior)
                {
                    return RemoveBehavior(listener);
                }
            }
            // still didn't find it so try to find it in collision listeners
            foreach (CollisionListener listener in m_collisionEventListeners)
            {
                if (listener.Behavior == behavior)
                {
                    return RemoveBehavior(listener);
                }
            }
            // try to find it in the disappear behaviors
            foreach (DisappearListener listener in m_disappearEventListeners)
            {
                if (listener.Behavior == behavior)
                {
                    return RemoveBehavior(listener);
                }
            }
            // finally try to find it in property change listeners
            foreach (StandardListener listener in m_propertyChangeEventListeners)
            {
                if (listener.Behavior == behavior)
                {
                    return RemoveBehavior(listener);
                }
            }
            return false;
        }

        /// <summary>
        /// Searches current behaviors for the instance of the IEventChecker passed in.  Removes the first 
        /// instance found so it will no longer be executed when its event occurs.
        /// </summary>
        /// <param name="eventChecker">The EventChecker parameter returned as part of an EventListener from AddBehavior</param>
        /// <returns>true if the behavior is successfully removed; otherwise, false.  
        /// This method also returns false if the behavior was not found.
        /// In the event that the BehaviorOwner is currently executing its behaviors, 
        /// the event will be queued for later removal and the function will immediately return true.</returns>
        public bool RemoveBehavior(IEventChecker eventChecker)
        {
            // first look in standard listeners
            foreach (StandardListener listener in m_standardEventListeners)
            {
                if (listener.EventChecker == eventChecker)
                {
                    return RemoveBehavior(listener);
                }
            }
            // then look in property change listeners
            foreach (StandardListener listener in m_propertyChangeEventListeners)
            {
                if (listener.EventChecker == eventChecker)
                {
                    return RemoveBehavior(listener);
                }
            }
            return false;
        }

        /// <summary>
        /// Removes the behavior defined by the EventListener returned by AddBehavior so it will no 
        /// longer be executed when its event occurs.
        /// </summary>
        /// <param name="behaviorToRemove">The reference returned from AddBehavior to a behavior of this actor or scene.</param>
        /// <returns>true if behaviorToRemove is successfully removed; otherwise, false. 
        /// This method also returns false if behaviorToRemove was not found. 
        /// In the event that the BehaviorOwner is currently executing its behaviors, 
        /// the event will be queued for later removal and the function will immediately return true.</returns>
        public bool RemoveBehavior(EventListener behaviorToRemove)
        {
            Type behaviorType = behaviorToRemove.GetType();

            if (behaviorType == typeof(StandardListener))
            {
                if (m_queueRemoves)
                {
                    behaviorToRemove.QueuedForRemoval = true;
                    m_eventsToRemove.Add(behaviorToRemove);
                    return true;
                }
                else
                {
                    StandardListener removeMe = (StandardListener)behaviorToRemove;
                    if (removeMe.EventChecker.GetType().Equals(typeof(CollisionEndChecker)))
                    {
                        m_scene.RemoveCollisionEndListener((CollisionEndChecker)removeMe.EventChecker).Then(() => Game.EventListenerCount--);
                    }
                    else if (removeMe.EventChecker is IPropertyEventChecker)
                    {
                        return m_propertyChangeEventListeners.Remove(removeMe).Then(() => Game.EventListenerCount--);
                    }
                    return m_standardEventListeners.Remove(removeMe).Then(() => Game.EventListenerCount--);
                }
            }
            else if (behaviorType == typeof(CollisionListener))
            {
                CollisionListener collisionListener = (CollisionListener)behaviorToRemove;
                m_collisionEventListeners.Remove(collisionListener);
                return m_scene.RemoveCollisionListener(collisionListener).Then(() => Game.EventListenerCount--);
            }
            else if (behaviorType == typeof(DisappearListener))
            {
                DisappearListener removeMe = (DisappearListener)behaviorToRemove;
                // don't need to add to any queue since we're deleting the actor anyway
                behaviorToRemove.QueuedForRemoval = true;
                if (m_queueDisappearRemoves)
                {
                    return true;
                }
                else
                {
                    return m_disappearEventListeners.Remove(removeMe).Then(() => Game.EventListenerCount--);
                }
            }
            else
            {
                throw new NotImplementedException(
                    Utils.ErrorMessagePrefix +
                    "Don't know how to remove an event listener of type '" +
                    behaviorType +
                    "'.");
            }
        }

        public void RemoveBehaviors()
        {
            List<EventListener> removeThese = new List<EventListener>();

            foreach (CollisionListener removeMe in m_collisionEventListeners)
            {
                removeThese.Add(removeMe);
            }
            foreach (StandardListener removeMe in m_standardEventListeners)
            {
                removeThese.Add(removeMe);
            }
            foreach (DisappearListener removeMe in m_disappearEventListeners)
            {
                removeThese.Add(removeMe);
            }

            foreach (StandardListener removeMe in m_propertyChangeEventListeners)
            {
                removeThese.Add(removeMe);
            }

            foreach (EventListener removeMe in removeThese)
            {
                RemoveBehavior(removeMe);
            }


        } // end method

        public abstract Canvas GetCanvasRoot();

        public Point GetObjectCenter()
        {
            return new Point(
                GetCenterX(),
                GetCenterY()
            );
        }

        public double GetCenterX()
        {
            return X + (Width * 0.5);
        }

        public double GetCenterY()
        {
            return Y + (Height * 0.5);
        }

        private bool m_mouseEnterLeaveListenerAdded;
        /// <summary>
        /// Call this when adding an enter, hover or leave listener
        /// </summary>
        internal void AddMouseHoverEnterOrLeaveListener()
        {
            if (m_mouseEnterLeaveListenerAdded)
            {
                return;
            }
            else
            {
                Canvas mouseCanvas = GetCanvasRoot();

                mouseCanvas.MouseEnter += new MouseEventHandler(mouseCanvas_MouseEnter);
                mouseCanvas.MouseLeave += new MouseEventHandler(mouseCanvas_MouseLeave);
                m_mouseEnterLeaveListenerAdded = true;

                mouseCanvas.IsHitTestVisible = true;
            }
        }

        public MouseEventArgs HasMouseLeft()
        {
            return m_mouseLeaveArgs;
        }
        private MouseEventArgs m_mouseLeaveArgs;
        void mouseCanvas_MouseLeave(object sender, MouseEventArgs args)
        {
            m_mouseEnterArgs = null;
            m_mouseLeaveArgs = args;
        }

        public MouseEventArgs HasMouseEntered()
        {
            return m_mouseEnterArgs;
        }
        private MouseEventArgs m_mouseEnterArgs;
        void mouseCanvas_MouseEnter(object sender, MouseEventArgs args)
        {
            m_mouseLeaveArgs = null;
            m_mouseEnterArgs = args;
        }

        private bool m_mouseLeftButtonListenerAdded;
        internal void AddMouseLeftButtonListener()
        {
            if (m_mouseLeftButtonListenerAdded)
            {
                return;
            }
            else
            {
                Canvas mouseCanvas = GetCanvasRoot();

                mouseCanvas.MouseLeftButtonDown += new MouseButtonEventHandler(mouseCanvas_MouseLeftButtonDown);
                mouseCanvas.MouseLeftButtonUp += new MouseButtonEventHandler(mouseCanvas_MouseLeftButtonUp);
                m_mouseLeftButtonListenerAdded = true;

                mouseCanvas.Cursor = Cursors.Hand;

                mouseCanvas.IsHitTestVisible = true;
            }
        }

        internal void ClearMouseArgsForNextUpdate()
        {
            m_mouseLeftButtonDownThisFrameArgs = null;
            m_mouseLeftButtonUpThisFrameArgs = null;
        }

        private MouseButtonEventArgs m_mouseLeftButtonUpArgs;
        private MouseButtonEventArgs m_mouseLeftButtonUpThisFrameArgs;
        internal void mouseCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs args)
        {
            if (m_mouseLeftButtonUpArgs == null)
            {
                m_mouseLeftButtonUpThisFrameArgs = args;
            }
            m_mouseLeftButtonUpArgs = args;
            m_mouseLeftButtonDownArgs = null;

            Console.Write("MSGE005: \"" + Name +
                "\" recieved MouseLeftButtonUp event (for actors this message may appear twice per mouse up, however the behavior will only be executed once)");
        }

        private MouseButtonEventArgs m_mouseLeftButtonDownArgs;
        private MouseButtonEventArgs m_mouseLeftButtonDownThisFrameArgs;
        void mouseCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs args)
        {
            if (m_mouseLeftButtonDownArgs == null)
            {
                m_mouseLeftButtonDownThisFrameArgs = args;
            }
            m_mouseLeftButtonDownArgs = args;
            m_mouseLeftButtonUpArgs = null;
            if (this.IsActor) m_game.RegisterForMouseUp((Actor)this);

            Console.Write("MSGE004: \"" + Name + "\" received MouseLeftButtonDown event");
        } // end method

        /// <returns>The MouseEventArgs from when the left mouse button was pressed if the button is down.  Otherwise, returns null.</returns>
        public MouseButtonEventArgs IsMouseLeftButtonDown()
        {
            return m_mouseLeftButtonDownArgs;
        }

        public MouseButtonEventArgs IsMouseLeftButtonDownThisFrame()
        {
            return m_mouseLeftButtonDownThisFrameArgs;
        }

        public MouseButtonEventArgs IsMouseLeftButtonUp()
        {
            return m_mouseLeftButtonUpArgs;
        }
        public MouseButtonEventArgs IsMouseLeftButtonUpThisFrame()
        {
            return m_mouseLeftButtonUpThisFrameArgs;
        }

        public void ClearMouseEventsForPause()
        {
            if (m_mouseLeftButtonDownArgs != null)
            {
                mouseCanvas_MouseLeftButtonUp(null, m_mouseLeftButtonDownArgs);
            }

            if (HasMouseEntered() != null)
            {
                mouseCanvas_MouseLeave(null, HasMouseEntered());
            }
        }

#if !PHONE
        #region CustomCodeSupport
        Dictionary<string, object> customDict = new Dictionary<string, object>();

        public Microsoft.JScript.Runtime.GameCreatorStuff.Vector2 GetCenter()
        {
            return new Microsoft.JScript.Runtime.GameCreatorStuff.Vector2()
            {
                X = GetCenterX(),
                Y = GetCenterY()
            };
        }
        [SpecialName]
        public new object GetBoundMember(string name)
        {
            var invokedListener = m_standardEventListeners.FirstOrDefault(
                (listener) =>
                    (listener.BehaviorName != null &&
                    listener.BehaviorName.Equals(name))
                );
            if (invokedListener != null)
            {
                return ((Action)(() =>
                {
                    invokedListener.Behavior.Invoke(this, null);
                }));
            }
            return base.GetBoundMember(name);
        }

        public void AddEventListener(
            String eventName,
            Microsoft.JScript.Runtime.Types.JSObject eventArgs,
            Microsoft.JScript.Runtime.Types.FunctionObject invokeFunction
            )
        {
            //TODO: do something more than just the every frame event
            IEventChecker checker = null;
            switch (eventName)
            {
                case "Timer":
                case "timer":
                    {
                        if (
                            eventArgs != null &&
                            !(eventArgs["minValue"] is Microsoft.JScript.Runtime.Types.UnDefined) &&
                            !(eventArgs["maxValue"] is Microsoft.JScript.Runtime.Types.UnDefined)
                            )
                        {
                            if (eventArgs["minValue"] != eventArgs["maxValue"])
                            {
                                checker = new RandomIntervalChecker(
                                    m_game,
                                    Convert.ToDouble(eventArgs["minValue"]),
                                    Convert.ToDouble(eventArgs["maxValue"]));
                            }
                            else
                            {
                                checker = new RegularIntervalChecker(m_game, Convert.ToDouble(eventArgs["minValue"]));
                            }
                        }
                        else if (eventArgs != null && !(eventArgs["interval"] is Microsoft.JScript.Runtime.Types.UnDefined))
                        {
                            checker = new RegularIntervalChecker(m_game, Convert.ToDouble(eventArgs["interval"]));
                        }
                        else
                        {
                            checker = new EveryFrameChecker(m_game);
                        }
                        break;
                    }
            }
            AddBehavior(
                new StandardListener(
                    m_game,
                    this,
                    null,
                    new Microsoft.Popfly.GameCreator.GameEngine.Behaviors.JSRuntime.JSRuntimeExtensions.InvokedFunction(
                        this,
                        invokeFunction
                        ),
                    null,
                    null,
                    checker
                    )
                );
        }
        public void RemoveEventListener(
            String eventName,
            Microsoft.JScript.Runtime.Types.FunctionObject invokeFunction
            )
        {
            RemoveBehavior(eventName, invokeFunction);
        }

        #endregion
#endif

    } // end behaviorowner class
} // end namespace
